﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using Google.Protobuf;
using LitJson;
using mb;

namespace libmp
{

    public class User : Mb.UserInfo
    {
        static ILog logger = App.logger;
        static API.IStartOption startOption = App.StartOption;

        //版本号，写到保存文件里去，以便支持升级兼容
        static int VERSION_201904 = 201904;
        static int VERSION_20190430 = 20190430;
        static int VERSION_NOW = VERSION_20190430;

        public delegate void OnChangedType(User user);
        public OnChangedType OnChanged;

        public string localPath;
        public User()
        {
            OnChanged += delegate { };
            Reset();
        }

        public void Reset()
        {

        }

        public void Save(string path = null)
        {
            path = path??localPath;
            WriteTo(new FileStream(path, FileMode.CreateNew));
            App.logger.Log("user data save", path);
        }

        void LoadCompatible()
        {
            // App.logger.Log($"UserInfo.LoadCompatible, version:[{this.version}->{VERSION_NOW}]");
            // string id = this.id;
            // this.Reset();
            // this.id = id;
            // this.version = VERSION_NOW;
            // this.seenMovieList = new List<int>();
        }

        public void Update(UserInfoData InfoData)
        {
            token = InfoData.token;
            id = InfoData.id;
            name = InfoData.name;
            phone = InfoData.phone;
            email = InfoData.email;
            viewsNums = InfoData.viewsNums;
            balance = InfoData.balance;
            userLevel = InfoData.userLevel;
            userHeadPic = InfoData.userHeadPic;
            dueDate = InfoData.dueDate;
            changeDate = InfoData.changeDate;
            Save();
        }

        public bool isVideoInHistory(int vid)
        {
            return this.seenMovieList.Contains(vid);
        }

        public void addVideoToHistory(int vid)
        {
            if (!isVideoInHistory(vid))
            {
                seenMovieList.Add(vid);
                viewsNums--;
            }
            else
            {
                seenMovieList.Remove(vid);
                seenMovieList.Add(vid);
            }
            logger.Log("addVideoToHistory", vid, viewsNums);
            Save();
        }

        public bool CanWatchVideo(int vid)
        {
            if (isVideoInHistory(vid)) return true;
            if (IsVip()) return true;
            if (viewsNums > 0) return true;

            return false;
        }
        public bool IsVip()
        {
            if (dueDate.Length > 0)
            {
                DateTime dt = DateTime.Now;
                var nowTime = dt.ToString("yyyy-MM-dd");
                DateTime dt1 = Convert.ToDateTime(dueDate);
                DateTime dt2 = Convert.ToDateTime(nowTime);
                int compNum = DateTime.Compare(dt1, dt2);
                if (compNum >= 0)
                {
                    return true;
                }
            }
            return false;
        }
        //-///////////////////////////////////////
        #region me
        public static User me;
        public static void Init()
        {
            var mePath = App.HotStorageRoot.Substring(0, App.HotStorageRoot.LastIndexOf("/")) + "/user.json";
            //方便测试时每次新建用户
            if (startOption.GetBoolValue("clearUserInfo") && File.Exists(mePath))
            {
                App.logger.Log("User.ClearMe");
                File.Delete(mePath);
            }

            me = new User() { localPath = mePath };
        }

        public void Load()
        {
            try
            {
                var strInfo = File.ReadAllText(localPath);
                me = LitJson.JsonMapper.ToObject<User>(strInfo);
                if (me.version != VERSION_NOW)
                {
                    me.LoadCompatible();
                    me.Save();
                }
            }
            catch (FileNotFoundException e)
            {
                App.logger.Log("user data not exist");
                me = new User();
                me.Save();
            }
            catch (Exception e)
            {
                App.logger.Log("load userdata error", e);
                me = new User();
                me.Save();
            }

            App.logger.Log("load me!!!!", me.id, me.name, me.phone);
        }

        #endregion 

        static byte[] passwd = ASCIIEncoding.ASCII.GetBytes("xiaoting");

        public async void Fetch()
        {
            try
            {
                //var res = await gRPC.Instance.ServiceClient.FetchAsync(new Mb.UserFetchRequest() { Id = this.id, });
                var res = gRPC.Instance.ServiceClient.Fetch(new Mb.UserFetchRequest() { Id = this.id, });
                logger.Log("Fetch ok", res.Id, res.Name, res.Balance, "<<<<<");
            }
            catch (Exception e)
            {
                logger.Log("Fetch fail", e);
            }
        }
        public void NotifyVisit()
        {
            try
            {
                gRPC.Instance.ServiceClient.NotifyAsync(new Mb.NotifyRequest() { Id = this.id, Type = Mb.NotifyRequest.Types.Type.Login });
                logger.Log("NotifyVisit ok", "<<<<<");
            }
            catch (Exception e)
            {
                logger.Log("NotifyVisit fail", e);
            }
        }

        public void Fetch2()
        {
            var baseUrl = App.CurrentServerUrl;
            var url = $"http://{baseUrl}/user/fetch";
            logger.Log("fetch user", url);

            var body = LitJson.JsonMapper.ToJson(new { token = libmp.User.me.token, id = libmp.User.me.id });
            var ebody = mb.Util.Encrypt(body, passwd);
            var dbody = mb.Util.Decrypt(ebody, passwd);
            logger.Log("body---------", body, ebody, dbody == body);
            body = "mbdata:" + ebody;
            body = ebody;
            Http.Option opt = null;
            var res = Http.MakeRequest(opt = new Http.Option
            {
                Url = url,
                    Method = HttpMethod.Post,
                    Body = body,
                    ContentType = "text/mbec",
                    TimeoutSec = 5,
                    OnFinish = (ok, code, msg) =>
                    {
                        try
                        {
                            if (code != 200)
                            {
                                logger.Log("User.Fetch failed/1", ok, code);
                                this.token = "";
                                return;
                            }
                            logger.Log("User.Fetch header", opt.Response.Content.Headers.ContentType);
                            msg = mb.Util.Decrypt(msg, passwd);

                            var jmsg = LitJson.JsonMapper.ToObject(msg);
                            var err = jmsg.ContainsKey("error") ? jmsg["error"].ToString() : null;
                            if (err != null)
                            {
                                logger.Log("User.Fetch failed/2", err);
                                this.token = "";
                            }
                            else
                            {
                                logger.Log("finish loadMe", url, ok, code, msg);
                                var newUser = LitJson.JsonMapper.ToObject<libmp.User>(msg);
                                this.name = newUser.name;
                                this.phone = newUser.phone;
                                this.email = newUser.email;
                                this.viewsNums = newUser.viewsNums;
                                this.balance = newUser.balance;
                                this.userLevel = newUser.userLevel;
                                this.userHeadPic = newUser.userHeadPic;
                                this.dueDate = newUser.dueDate;
                                this.changeDate = newUser.changeDate;

                                this.Save();
                                this.OnChanged(this);
                            }
                        }
                        catch (Exception e)
                        {
                            logger.Log("User.Fetch failed/3", e, e.Data["StackTrace"]?.ToString(), msg);
                            this.token = "";
                        }
                    },
            });
        }

        public void Notify(string type, string extra = null)
        {
            var url = $"http://{UserServer}/user/notify";
            var jobj = new JsonData();
            jobj["id"] = this.id;
            jobj["type"] = type;
            jobj["deviceInfo"] = Util.GetHardwareInfo();

            if (type == "register")
            {
                jobj["phone"] = this.phone;
                jobj["name"] = this.name;
            }

            if (type == "login") { }

            if (extra != null)
                jobj["extra"] = JsonMapper.ToObject(extra);

            logger.Log("notify >>>>>", type, id, url, extra);
            var res = Http.MakeRequest(new Http.Option
            {
                Url = url,
                    Method = HttpMethod.Post,
                    Body = LitJson.JsonMapper.ToJson(jobj),
                    OnFinish = (ok, code, msg) =>
                    {
                        // logger.Log("notify <<<<<", ok, code, msg);
                    }
            });
        }
        public void UpdateViewNums(string id, int viewsNums, bool changeMax)
        {
            var baseUrl = App.CurrentServerUrl;
            var body = LitJson.JsonMapper.ToJson(new { id = id, viewsNums = viewsNums, changeMax = changeMax });
            var url = $"http://{baseUrl}/user/updateViewNums";
            var res = Http.MakeRequest(new Http.Option
            {
                Url = url,
                    Method = HttpMethod.Post,
                    Body = body,
                    OnFinish = (ok, code, msg) =>
                    {
                        logger.Log("msg:" + msg);
                        if (code == 500)
                        {
                            logger.Log("----更新错误");
                        }
                        else
                        {
                            logger.Log("----更新成功");
                        }

                    },
                    OnProgress = (total, now) =>
                    {
                        logger.Log("progress", total, now);
                    }
            });
        }

        string UserServer
        {
            get
            {
                // var servers = App.AServerLoader.GetAvailabeServers(ServerLoader.ServerType.User);
                return App.CurrentServerUrl;
            }
        }
    }

}